package com.xiyuan.smartutils.template.engine.expression.primitive;

import com.xiyuan.smartutils.Classes;
import com.xiyuan.smartutils.Validates;
import com.xiyuan.smartutils.template.engine.VariableMap;
import com.xiyuan.smartutils.template.engine.exception.ExpressionException;
import com.xiyuan.smartutils.template.engine.expression.Expression;

import java.lang.reflect.Field;

/**
 * 变量原型，格式为字母或下划线开头，(字母、下划线和数字)连贯
 * 
 * @version v1.0.0 @author lgz 2020年10月31日 新建与整理
 */
public class _Variable extends Primitive
{
    private static final long serialVersionUID = 1L;
    private String variableName;// 这是变量名
    private Class<?> cls;
    
    public _Variable(String path, int line, int column, String value)
    {
        super(path, line, column);
        this.variableName = value;
    }
    
    @Override
    public int getType()
    {
        return VARIABLE;
    }
    
    @Override
    protected Object build(VariableMap variableMap)
    {
        // 1 判断是否有类
        if (this.cls != null)
            return this.cls;
        
        Object obj = null;
        String key = this.toString();
        
        // 1.判断是不是变量，如果是返回变量值
        if (variableMap.has(variableName))//
            return variableMap.get(key);
        
        // 2 父表达式结果取值
        if (target != null)
        {
            obj = target.execute(variableMap);
            // 不是java 命名规则的情况下，父元素返回结果为null 则直接抛找不到属性异常
            if (!Validates.isJavaNameIdentifier(key) && obj == null)
                throw new ExpressionException(this, "无法获取属性[" + variableName + "],表达式{" + target + "}返回值为 null");
            
            if (obj != null)// 如果父元素又返回结果则variable 是元素的属性
            {
                Field field = getField(obj, variableName);
                if (field != null)
                    return Classes.getFieldValue(obj, field);
                
                throw new ExpressionException(this, "变量表达式 {" + target + "}结果未找到“" + variableName + "”属性");
            }
        }
        
        // 3.判断是否是java系统类名String,List等
        Class<?> cls = VariableMap.getJavaClass(key);
        if (cls != null)
            return cls;// 认为是通过类去调用静态属性或方式，直接返回null，调用者再从buildClass获取clazz去调用
            
        // 3.判断是否从系统工具包中获取工具类，Validates 或者 com.xiyuan.smartutils.Validates
        cls = VariableMap.getSystemClass(key);
        if (cls != null)
            return (this.cls = cls);
        
        // // 4从系统全局找类
        // cls = Global.getClass(key);
        // if (cls != null)
        //     return (this.cls = cls);
        
        // 5.最后认为是类全称，如com.xiyuan.smartutils.Validates全名，或没有包名的类，如ATest
        cls = Classes.forName(key);
        if (cls != null)// 最少可能且最慢放最后
            return (this.cls = cls);
        
        // 都不对，就没办法了啦！
        return null;
    }
    
    public _Variable setTarget(Expression target)
    {
        super.setTarget(target);
        return this;
    }
    
    @Override
    public String toString()
    {
        StringBuilder strb = new StringBuilder();
        if (target != null)
            strb.append(target.toString()).append(".");
        
        return strb.append(variableName).toString();
    }
    
    public String getVariableName()
    {
        return variableName;
    }
}
